from sqlalchemy import Column, Integer, String, Float, Boolean
from .base import Base, db
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from app import login_manager
from app.libs.helper import is_isbn_or_key
from app.spider.ys_book import YsBook
from app.models.gift import Gift
from app.models.wish import Wish
from app.models.drift import Drift
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import current_app
from app.libs.enums import PendingStatus
from math import floor


class User(Base, UserMixin):
    # __tablename = 'users'
    id = Column(Integer, primary_key=True)
    nickname = Column(String(24), nullable=False, comment='昵称')
    phone_number = Column(String(18), unique=True, comment='手机号码')
    _password = Column('password', String(128), nullable=False, comment='密码')
    email = Column(String(50), unique=True, nullable=False, comment='邮箱')
    confirmed = Column(Boolean, default=False)
    beans = Column(Float, default=0, comment='鱼豆')
    send_counter = Column(Integer, default=0)
    receive_counter = Column(Integer, default=0)
    wx_open_id = Column(String(50))
    wx_name = Column(String(32))

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, raw):
        self._password = generate_password_hash(raw)

    def check_password(self, raw):
        """
        验证用户密码是否正确
        :param raw:
        :return:
        """
        return check_password_hash(self._password, raw)

    def can_save_to_list(self, isbn):
        """
        验证isbn是否合法
        :param isbn:
        :return:
        """
        # isbn编号是否符合规范
        if is_isbn_or_key(isbn) != 'isbn':
            return False
        # 是否存在isbn对应的书籍
        ys_book = YsBook()
        ys_book.search_by_isbn(isbn)
        if not ys_book.first:
            return False
        # 赠送者不能同时赠送相同的书籍多次，赠送者不能既是赠送者又是索要者
        # 当前图书既不在赠送者的赠送清单中，也不在赠送者的心愿清单中
        gifting = Gift.query.filter_by(uid=self.id, isbn=isbn, launched=False).first()
        wishing = Wish.query.filter_by(uid=self.id, isbn=isbn, launched=False).first()
        if gifting or wishing:
            return False
        else:
            return True

    # def get_id(self):
    #     return self.id

    @login_manager.user_loader
    def get_user(uid):
        return User.query.get(int(uid))

    def generate_token(self, expiration=600):
        """
        生成用户token
        :param expiration:
        :return:
        """
        s = Serializer(current_app.config['SECRET_KEY'], expiration)
        return s.dumps({'uid': self.id}).decode('utf-8')

    @staticmethod
    def reset_password(token, new_password):
        """
        修改用户密码
        :param token:
        :param new_password:
        :return:
        """
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token.encode('utf-8'))
        except:
            return False
        uid = data.get('uid')
        with db.auto_commit():
            user = User.query.get_or_404(uid)
            user.password = new_password
        return True

    def can_send_drift(self):
        """
        判断用户是否可以索取书籍
        :return:
        """
        if self.beans < 1:
            return False
        # 用户赠送成功的书籍数量
        success_gift_count = Gift.query.filter_by(
            uid=self.id, launched=True
        ).count()
        # 用户索取成功的书籍的数量
        success_recive_count = Drift.query.filter_by(
            requester_id=self.id, pending=PendingStatus.Success
        ).count()
        # 用户每索取一本书必须赠送成功两本
        return True if floor(success_recive_count / 2) <= floor(success_gift_count) else False

    @property
    def summary(self):
        return dict(
            nickname=self.nickname,
            beans=self.beans,
            email=self.email,
            send_receive=str(self.send_counter) + '/' + str(self.receive_counter)
        )
